﻿using CoachingOrganizer.Logic.Helpers;
using CoachingOrganizer.Logic.Logic.Tools;
using CoachingOrganizer.Logic.Models.Tools;
using CoachingOrganizer.Toolkit.Events;
using CoachingOrganizer.Toolkit.Threading.CollectionsDecorators;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoachingOrganizer.Logic.Models.Common
{
    public class GoalModel
    {
        private readonly SimpleCollectionLoadDecorator<ToolModelBase> _tools;
        private ToolModelBase _currentTool;
        private string _title;
        private string _description;
        private string _expectedResultVolume;

        public ToolModelBase CurrentTool
        {
            get { return _currentTool; }
            set
            {
                _currentTool = value;
                OnCurrentToolChanged();
            }
        }

        public IEnumerable<ToolModelBase> Tools
        {
            get { return _tools.Items; }
        }

        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }

        public string Description
        {
            get { return _description; }
            set { _description = value; }
        }

        public string ExpectedResultVolume
        {
            get { return _expectedResultVolume; }
            set { _expectedResultVolume = value; }
        }

        public event EventHandler CurrentToolChanged;

        public event EventHandler ToolsChanged
        {
            add { _tools.ItemsChanged += value; }
            remove { _tools.ItemsChanged -= value; }
        }

        public event NotifyCollectionChangedEventHandler ToolsCollectionChanged
        {
            add { _tools.ItemsCollectionChanged += value; }
            remove { _tools.ItemsCollectionChanged -= value; }
        }

        internal Func<ActionResult<IEnumerable<ToolLogicBase>>> EnumerateToolsDelegate;

        internal Func<Type, Action<CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.IToolInfo>, ActionResult<ToolLogicBase>> AddNewToolDelegate;

        internal Func<ActionResult> RemoveDelegate;

        internal Func<ActionResult> SaveDelegate;

        public GoalModel()
        {
            _tools = new SimpleCollectionLoadDecorator<ToolModelBase>(EnumerateTools);
        }

        public async Task LoadToolsAsync(System.Threading.CancellationToken cancelLoad)
        {
            await Task.Run(() => _tools.FillItemsList(), cancelLoad);
        }

        public async Task<ActionResult> AddNewMoodLevel()
        {
            return await AddNewTool<CoachingOrganizer.Logic.Logic.Tools.MoodLevel.MoodLevelLogic>(null);
        }

        public async Task<ActionResult> AddNewEmotionsPack()
        {
            return await AddNewTool<CoachingOrganizer.Logic.Logic.Tools.EmotionsPack.EmotionsPackLogic>(null);
        }

        public async Task<ActionResult> AddNewMoneyCalculation()
        {
            return await AddNewTool<CoachingOrganizer.Logic.Logic.Tools.MoneyCalculation.MoneyCalculationLogic>(null);
        }

        internal async Task<ActionResult> AddNewTool<TToolLogic>(Action<CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.IToolInfo> initCallback) where TToolLogic : ToolLogicBase
        {
            return await Task.Run(() =>
            {
                ActionResult<ToolModelBase> newToolResult;
                if (AddNewToolDelegate != null)
                {
                    ActionResult<ToolLogicBase> getResult = AddNewToolDelegate(typeof(TToolLogic), initCallback);
                    newToolResult = getResult.IsValid ? ActionResult<ToolModelBase>.GetValidResult(getResult.Result.BaseModel) : ActionResult<ToolModelBase>.GetErrorResult(getResult);
                }
                else
                    newToolResult = ActionResult<ToolModelBase>.GetErrorResult(new NotSupportedException());
                if (newToolResult.IsValid)
                    _tools.ModifyCollection(col => col.Add(newToolResult.Result));
                return newToolResult.IsValid ? ActionResult.ValidResult : ActionResult.GetErrorResult(newToolResult);
            });
        }

        public void ModifyToolsCollection(Action<IList<ToolModelBase>> modificationDelegate)
        {
            _tools.ModifyCollection(modificationDelegate);
        }

        public async Task<ActionResult> Remove()
        {
            Func<ActionResult> removeDelegate = RemoveDelegate;
            return removeDelegate == null ? ActionResult.GetErrorResult(new NotSupportedException()) : await Task.Run(() => removeDelegate());
        }

        public async Task<ActionResult> Save()
        {
            Func<ActionResult> saveDelegate = SaveDelegate;
            return saveDelegate == null ? ActionResult.GetErrorResult(new NotSupportedException()) : await Task.Run(() => saveDelegate());
        }

        private ActionResult<IEnumerable<ToolModelBase>> EnumerateTools()
        {
            return UpdateHelper.EnumerateModels(EnumerateToolsDelegate, l => l.BaseModel);
        }

        protected virtual void OnCurrentToolChanged()
        {
            EventHandler handler = CurrentToolChanged;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }
    }
}
